#include "dominion.h"
#include "dominion_helpers.h"
#include "sput/sput.h"
#include <stdlib.h>
#include <time.h>

struct gameState *testState;

static void test_card(void)
{
    int *bonus = NULL;

    int card = mine;

    int choice1;
    int choice2;
    int choice3 = -1;   // unused

    // set to 'curse' if card doesn't take that choice as an argument; otherwise
    // set to 'treasure_map'.
    int choice1_lim = treasure_map + 1;
    int choice2_lim = treasure_map + 1;

    int has_treasure;
    int gained_card;
    int init_choice1_count;
    int post_choice1_count;
    int init_choice2_count;
    int post_choice2_count;
    int init_copper_count;
    int init_silver_count;
    int init_gold_count;
    int init_treasure_count;

    int init_deck_count;
    int init_hand_count;
    int init_num_buys;
    int init_ops_hand_counts;

    int handPos;
    int player;
    int res;
    int numPlayers;

    int kc[10] = {adventurer, council_room, feast, gardens, mine, remodel,
                  smithy, village, baron, great_hall
                 };

    // iterate through all player counts
    for(numPlayers = 2; numPlayers <= MAX_PLAYERS; numPlayers++) {
        // check performance when player does and doesn't have treasure in hand
        for(has_treasure = 0; has_treasure <= 1; has_treasure++) {
            initializeGame(numPlayers, kc, rand(), testState);

            // iterate though all cards
            for(choice1 = curse - 1; choice1 <= choice1_lim; choice1++) {
                for(choice2 = curse - 1; choice2 <= choice2_lim; choice2++) {
                    //iterate over players
                    for(player = 0; player < testState->numPlayers; player++) {
                        // set turn to current player
                        testState->whoseTurn = player;

                        // this is set to one if card was gained
                        gained_card = 0;

                        // place card in current hand position
                        handPos = 0;
                        testState->hand[player][handPos] = card;

                        init_hand_count = testState->handCount[player];

                        if(has_treasure) {
                            // place treasure in hand
                            testState->hand[player][handPos + 1] = copper;
                            testState->hand[player][handPos + 2] = silver;
                            testState->hand[player][handPos + 3] = gold;
                        } else {
                            replace_card(player, testState, copper, curse);
                            replace_card(player, testState, silver, curse);
                            replace_card(player, testState, gold, curse);
                        }


                        init_choice1_count = count_in_hand(player, testState, choice1);
                        init_choice2_count = count_in_hand(player, testState, choice2);

                        init_copper_count = count_in_hand(player, testState, copper);
                        init_silver_count = count_in_hand(player, testState, silver);
                        init_gold_count = count_in_hand(player, testState, silver);
                        init_treasure_count = init_copper_count + init_silver_count + init_gold_count;

                        init_deck_count = testState->deckCount[player];
                        // set buys to one to initialize turn
                        init_num_buys = testState->numBuys = 1;
                        // other players' hand counts
                        init_ops_hand_counts = ops_hand_counts(player, testState);

                        // play the card
                        res = cardEffect(card, choice1, choice2, choice3, testState, handPos, bonus);

                        if(init_treasure_count == 0) {
                            sput_fail_unless(res == -1, "failed to gain treasure when no treasure card to trash");
                        }

                        if(choice1 != copper && choice1 != silver && choice1 != gold) {
                            sput_fail_unless(res == -1, "failed to gain treasure card when trashed card not a treasure card");
                        }

                        if(choice1 < curse || choice1 > treasure_map) {
                            sput_fail_unless(res == -1, "failed to gain treasure card when trashed card out-of-range");
                        }

                        if((getCost(choice1) + 3) < getCost(choice2)) {
                            sput_fail_unless(res == -1, "failed to gain treasure card when buy power insufficient");
                        }

                        if(res != -1) {
                            post_choice1_count = count_in_hand(player, testState, choice1);
                            post_choice2_count = count_in_hand(player, testState, choice2);
                            sput_fail_unless(testState->handCount[player] == init_hand_count - 1, "gained one card and trashed another, and discarded card");
                            if(choice1 != choice2) {
                                sput_fail_unless(post_choice1_count == init_choice1_count - 1, "trashed treasure card");
                                sput_fail_unless(post_choice2_count == init_choice2_count + 1, "gained additional treasure card");
                            } else {
                                sput_fail_unless(post_choice1_count == init_choice1_count, "trashed same treasure card");
                                sput_fail_unless(post_choice1_count == init_choice1_count, "gained same treasure card");
                            }
                        }


                        /* HERE'S WHERE WE TEST THE CARD'S EFFECT */


                        /* END TESTING CARD EFFECT */

                    }   /* player */
                }   /* choice1 */
            }   /* choice2 */
        }   /* has_treasure */
    }   /* numPlayers */
}

int main(int argc, char *argv[])
{
    // Seed random number generator
    srand(time(NULL));

    // Initialize game state
    testState = newGame();

    sput_start_testing();
    sput_enter_suite(__FILE__);

    sput_run_test(test_card);
    sput_finish_testing();

    free(testState);

    return sput_get_return_value();
}
